from fastapi import FastAPI
import uvicorn
from typing import Optional
from pydantic import BaseModel
from fastapi import Query, Body, status
from pydantic import validator, Field
from fastapi.responses import JSONResponse
from fastapi.exceptions import RequestValidationError
import pydantic
from fastapi import Depends

class Item(BaseModel):
    name: str
    price: float
    description: Optional[str] = None
    tax: Optional[float] = None


app = FastAPI()


async def common_page_size_parameters(page: Optional[int] = 1, size: int = Query(None, le=20)):
    return {
        'page': page,
        'size': size
    }


class PageLimitParam:
    def __init__(self, page: Optional[int] = 1, size: int = Query(None, le=20)):
        self.page = page
        self.size = size


class PageLimitParamModel(BaseModel):
    page: Optional[int] = 1
    size: int = Body(9, embed=True)
    name: str = Query('sdsd')

    @validator('size')
    def check_size(cls, v):
        print(v)
        return v


# http ':9999/item/23?key=hello'
@app.get('/item/{item_id}')
async def get_item(item_id: int, key: str, common: PageLimitParam = Depends(PageLimitParam)):
    return {'item_id': item_id, 'page': common.page, 'size': common.size, 'key': key}


# http post ':9999/item2/23?name=hello'  name=23
@app.post('/item2/{item_id}')
async def get_item2(age: int = Body(12, embed=True), common: PageLimitParamModel = Depends()):  # common永远从query里获取
    print('ssss')
    return {'page': common.page, 'size': common.size, 'name': common.name, 'age': age}


# http post ':9999/item3/23?name=hello'  name=23
@app.post('/item3/{item_id}')
async def get_item3(common: PageLimitParamModel):  # common永远从body里获取
    return {'page': common.page, 'size': common.size, 'name': common.name}


# http post ':9999/item4/23?name=hello'  age=23
@app.post('/item4/{item_id}')
async def get_item4(age: int = Body(..., embed=True)):  # 永远从query里获取
    print('ssss')
    return {'age': age}


# http  post ':9999/test'
@app.post('/test')
def test(i: int = Body(23, embed=True)):
    return {
        'i': i
    }


# http get ':9999/model' name=Tom price=19
@app.get('/model')
async def model(item: Item):
    return item


# http post ':9999/model2' name=Tom price=19
@app.post('/model2')
async def model(item: Item):
    return item


class ItemResponse(BaseModel):
    price: float
    description: Optional[str] = None
    tax: Optional[float] = None
    age: int = 18
    data: dict


@app.exception_handler(pydantic.error_wrappers.ValidationError)
async def handle_validation_error(request, exc):
    return JSONResponse(
        status_code=418,
        content={"message": f"Oops! ValidationError异常"},
    )


# 重写参数校验失败的异常
# @app.exception_handler(RequestValidationError)
# async def handle_validation_error(request, exc):
#     return JSONResponse(
#         status_code=418,
#         content={"message": f"参数错误 {str(exc)}"},
#     )


# http post ':9999/model3' name=Tom price=19
@app.post('/model3', response_model=ItemResponse)
async def model(item: Item):
    print(item, type(item))
    # item['data'] = {}  # 不能直接赋值
    item_resp: ItemResponse = ItemResponse(**item.dict(), data=None)  # 必须要加入data  否则在验证的时候就出现异常
    print(item_resp)
    return item_resp


@app.get('/status', status_code=status.HTTP_201_CREATED)
async def status():
    return {}


if __name__ == '__main__':
    uvicorn.run('__main__:app', port=9999, reload=True)
